package masterjava.common.server.gwt.rpc.controller;

import masterjava.common.server.gwt.rpc.RpcHandler;
import masterjava.common.shared.rpc.CustomRemoteService;
import masterjava.common.shared.rpc.Request;
import masterjava.common.shared.rpc.Response;
import masterjava.common.util.Util;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.HierarchicalBeanFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.annotation.Autowired;

import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.Map;

/**
 * User: Grigory Kislin
 * Date: 27/06/11
 */

public class CustomRpcController extends GwtRpcController implements CustomRemoteService, InitializingBean {
    private Map<Class<Request>, RpcHandler> requestMap = new HashMap<Class<Request>, RpcHandler>();

    @Autowired
    private  BeanFactory beanFactory;

    @Override
    public Response send(Request request) {
        try {
            logger.info("Handle "+request.getClass()+" request");
            return requestMap.get(request.getClass()).handlerRequest(request);
        } catch (Throwable e) {
            logger.treatThrowable("Request " + request.toString() + " handling failed", e);
            return null;  // dummy
        }
    }

    @PostConstruct
    public void afterPropertiesSet() throws Exception {
        BeanFactory factory = beanFactory;
        while (factory != null) {
            if (factory instanceof ListableBeanFactory) {
                Map<String, RpcHandler> beansMap = ((ListableBeanFactory) factory).getBeansOfType(RpcHandler.class);
                for (RpcHandler rm : beansMap.values()) {
                    Class<Request> reqClass = Util.getGenericParameter(rm, 0);
                    requestMap.put(reqClass, rm);
                    logger.debug(reqClass.getName() + " available for handling");
                }
                factory = (factory instanceof HierarchicalBeanFactory) ? ((HierarchicalBeanFactory) factory).getParentBeanFactory() : null;
            }
        }
    }
}
